export function isObject(target) {
    return typeof target === 'object' && target != null
}

export function isString(target) {
    return typeof target === 'string'
}

export function isNumber(target) {
    return typeof target === 'number'
}

export function isBoolean(target) {
    return typeof target === 'boolean'
}

export function isArray(target) {
    return Array.isArray(target)
}

export function isFunction(target) {
    return typeof target === 'function'
}

export function hasChanged(oldValue, value) {
    // 注意NaN !== NaN
    // 所以需要额外判断两个值不同时为NaN
    return oldValue !== value && !(Number.isNaN(oldValue) && Number.isNaN(value))
}

/**
 * @description: 深拷贝函数
 * @param {*} obj
 * @return {*}
 */
export function clone(item) {
    if (!item) { return item } // null, undefined values check

    let types = [ Number, String, Boolean ], 
        result

    // normalizing primitives if someone did new String('aaa'), or new Number('444');
    types.forEach(function(type) {
        if (item instanceof type) {
            result = type( item )
        }
    })

    if (typeof result == "undefined") {
        if (Object.prototype.toString.call( item ) === "[object Array]") {
            result = []
            item.forEach(function(child, index, array) { 
                result[index] = clone( child )
            });
        } else if (typeof item == "object") {
            // testing that this is DOM
            if (item.nodeType && typeof item.cloneNode == "function") {
                result = item.cloneNode( true )
            } else if (!item.prototype) { // check that this is a literal
                if (item instanceof Date) {
                    result = new Date(item)
                } else {
                    // it is an object literal
                    result = {};
                    for (let i in item) {
                        result[i] = clone( item[i] )
                    }
                }
            } else {
                // depending what you would like here,
                // just keep the reference, or create new object
                if (false && item.constructor) {
                    // would not advice to do that, reason? Read below
                    result = new item.constructor();
                } else {
                    result = item
                }
            }
        } else {
            result = item
        }
    }

    return result;
}

/**
 * @description: get Longest Increasing Sequence
 * 默认返回的是下标数组（因为服务于diff算法）
 * @param {Array} array
 * @param {Boolean} index default true
 * @return {Array} sequence
 */
export function getLIS(array, index = true) {
    if (array.length <= 1)
        return array

    let dp = new Array(array.length).fill(1)
    const sequences = []

    for (let i = 0; i < array.length; i++) {
        sequences.push((index ? [i] : [array[i]]))
        // 更新i之前的序列
        for (let j = 0; j < i; j++) {
            // 如果array[i]比array[j]大
            // 考虑更新j位的最长子序列长度
            if (array[i] > array[j] && dp[j] + 1 > dp[i]) {
                sequences[i] = [...sequences[j], (index ? i : array[i])]
                dp[i] = dp[j] + 1
            }
        }
    }

    const maxIndex = dp.indexOf(Math.max(...dp));
    return sequences[maxIndex]
}